技巧110 禁用内存溢出杀手

“内存溢出杀手”(OOM killer)听上去像是一个烂恐怖片或者严重的疾病,但是实际上它是Linux操作系统中决定宿主机耗尽内存后如何行动的一个线程。在操作系统耗尽硬件内存,使用了可供使用的交换区,把任何缓存文件移除出内存之后,会启动内存溢出杀手来决定下一步继续“杀死”什么进程。

问题

想要阻止容器被内存溢出杀手杀死。

解决方案

在启动容器的时候使用 --oom-kill-disable 标志。

似乎通过向Docker容器添加一个标志就可以解决。但是和往常一样,情况并没有那么简单。

代码清单16-1展示了如何为容器禁用内存溢出杀手。

代码清单16-1 --oom-kill-disable展示警告

$ docker run -ti --oom-kill-disable ubuntu sleep 1  ⇽--- 向正常的docker run命令添加--oom-kill-disable标志
 WARNING: Disabling the OOM killer on containers without setting a
➥ '-m/--memory' limit may be dangerous.   ⇽--- 输出警告说另一个标志可能也要设置

你看到的这一警告是很重要的。它告诉你使用这个设置来运行有危险,但是没告诉你原因。使用这一选项之所以危险,是因为当宿主机耗尽内存时,操作系统在“杀死”你的进程之前会“杀死”其他所有的用户进程。

有时候需要这样,比如你有一个想要防止其停运至关重要的基础设施——可能是一个用于宿主机上所有容器的审计或日志记录进程。即便如此,也要多思考这一选项对环境可能造成多大的破坏。例如,容器可能依赖同一台宿主机上运行的基础设施。如果运行的是一个OpenShift这样的容器平台,容器会在关键的平台进程被“杀死”后仍然运行。但是这些关键的基础设施最好在容器之前保持正常运行。

--memory 标志加入正常的 docker run 命令后,则不再输出警告,如代码清单16-2所示。

代码清单16-2 --oom-kill-disable不带有警告信息

$ docker run -ti --oom-kill-disable --memory 4M ubuntu sleep 1  ⇽--- 把--memory标志加到了正常的docker run命令中
 $  ⇽--- 本次没有看到警告信息

注意

可分配内存大小最小值是4 MB,MB代表兆字节。分配的内存大小也可以用GB(吉字节)来表示。

你可能想知道如何告知你的容器是否被内存溢出杀手“杀死”了。使用 docker inspect 命令可以轻松做到这一点,如代码清单16-3所示。

代码清单16-3 决定容器是否被内存溢出“杀死”了

$ docker inspect logger | grep OOMKilled
            "OOMKilled": false,

这个命令输出了容器被“杀死”的原因,包含是否被内存溢出杀手“杀死”。

讨论

给容器设置内存溢出杀手不需要拓展权限,也不需要是root用户——需要的只是可以访问 docker 命令。这也是在给未以root身份信任的未授权的用户 docker 命令的访问权限的时候要谨慎的原因(关于安全问题见第14章)。

这不仅仅是个安全问题,还是个稳定性问题。如果用户可以运行 docker ,他们可以运行一个渐渐泄露内存的进程(在生产环境很常见)。如果对那块内存没有边界,操作系统会在其他选项都用过的时候插手,首先“杀死”最费内存的用户进程(这是对Linux内存溢出杀手算法的简化,该算法已经饱经实战成长多年)。如果该容器是禁用了内存溢出杀手来运行的,那么,它就会踩踏宿主机上的其他所有容器,对用户造成更大的破坏和不稳定。

为了更加精细地管理内存,可以对容器使用 --oom-score-adj 标志来调整“内存溢出分数”。另一种可以满足目的的办法是禁用内核中的内存过量使用。这和全局禁用内存溢出杀手是一样的,因为内存仅在可分配的时候分配。然而,这可能会限制宿主机上可以运行的容器数量,这可能也不是你想要的。

一直以来,性能管理都是一门艺术!

results matching ""

    No results matching ""